﻿namespace Wintellect.LiveFx.Cloudboard
{
  using System;
  using System.Runtime.InteropServices;

  internal static class NativeMethods
  {

    //LRESULT SendMessage(HWND hWnd,
    //    UINT Msg,
    //    WPARAM wParam,
    //    LPARAM lParam
    //);
    [DllImport("User32", SetLastError = true, CharSet=CharSet.Auto)]
    private static extern int SendMessage(IntPtr hwnd, WindowMessage message, IntPtr wParam, IntPtr lParam);

    [DllImport("User32", EntryPoint="SendMessage", SetLastError = true, CharSet=CharSet.Auto)]
    private static extern IntPtr SendHotkeyMessage(IntPtr hwnd, HotkeyMessage message, IntPtr wParam, IntPtr lParam);

    //BOOL RegisterHotKey(HWND hWnd,
    //    int id,
    //    UINT fsModifiers,
    //    UINT vk
    //);    
    [DllImport("User32", SetLastError = true)]
    public extern static bool RegisterHotKey(IntPtr hWnd, int id, KeyModifier modifiers, KeyCode keycode);

    //BOOL UnregisterHotKey(HWND hWnd,
    //    int id
    //);
    [DllImport("User32", SetLastError = true)]
    public extern static bool UnregisterHotKey(IntPtr hWnd, int id);

    //int GetWindowText(          HWND hWnd,
    //    LPTSTR lpString,
    //    int nMaxCount
    //);
    [DllImport("User32", CharSet = CharSet.Auto, SetLastError = true)]
    public extern static int GetWindowText(IntPtr hWnd,
        System.Text.StringBuilder buffer,
        int bufferSize);

    //HWND GetForegroundWindow(VOID);
    [DllImport("User32")]
    public extern static IntPtr GetForegroundWindow();

    [DllImport("User32", SetLastError = true)]
    public static extern bool SetForegroundWindow(IntPtr hwnd);

    [DllImport("User32")]
    private extern static IntPtr GetFocus();

    [DllImport("Kernel32")]
    private extern static IntPtr GetCurrentThreadId();

    [DllImport("User32", CharSet = CharSet.Auto, SetLastError = true)]
    private extern static IntPtr GetWindowThreadProcessId(IntPtr handle, out uint processId);

    [DllImport("User32", CharSet = CharSet.Auto, SetLastError = true)]
    private extern static IntPtr AttachThreadInput(IntPtr threadToAttach, IntPtr threadToAttachTo, bool attaching);

    public static IntPtr GetForegroundFocus()
    {
	    IntPtr hwndFG = NativeMethods.GetForegroundWindow();
	    if (IntPtr.Zero == hwndFG) {
		    throw new System.ComponentModel.Win32Exception("GetForegroundWindow failed.");
	    }

      uint processId;
      IntPtr tid = NativeMethods.GetWindowThreadProcessId(hwndFG, out processId);
	    if (IntPtr.Zero ==  tid) {
		    throw new System.ComponentModel.Win32Exception("GetWindowThreadProcessId failed.");
	    }

      if (IntPtr.Zero == NativeMethods.AttachThreadInput(NativeMethods.GetCurrentThreadId(), tid, true)) {
        throw new System.ComponentModel.Win32Exception("AttachThreadInput failed.");
	    }

	    // this might be NULL if the foreground app has no focused window
	    // such as a console window
	    IntPtr hwndFocused = NativeMethods.GetFocus();

	    AttachThreadInput(GetCurrentThreadId(), tid, false);

	    return hwndFocused;
    }

    public static void SendWindowCopy(IntPtr hwndInput)
    {
      NativeMethods.SendMessage(hwndInput, WindowMessage.WM_COPY, IntPtr.Zero, IntPtr.Zero);
    }

    public static void SendWindowPaste(IntPtr hwndInput)
    {
      NativeMethods.SendMessage(hwndInput, WindowMessage.WM_PASTE, IntPtr.Zero, IntPtr.Zero);
    }

    public static void SendWindowText(IntPtr hwndInput, String text)
    {
      IntPtr pString = System.Runtime.InteropServices.Marshal.StringToHGlobalUni(text);
      try
      {
  		  NativeMethods.SendMessage(hwndInput, WindowMessage.WM_SETTEXT, IntPtr.Zero, pString);
      }
      finally
      {
        System.Runtime.InteropServices.Marshal.FreeHGlobal(pString);
      }
    }

    public static bool Paste(IntPtr window, IntPtr target)
    {
      // Inform the window/control that a tidbit is waiting for them on the clipboard
      NativeMethods.SetForegroundWindow(target);
      //NativeMethods.SendWindowText(target, textItem);
      NativeMethods.SendWindowPaste(target);


      return true;
    }

    [DllImport("user32.dll", EntryPoint = "CreateWindowEx", CharSet = CharSet.Unicode)]
    internal static extern IntPtr CreateWindowEx(
      int dwExStyle, 
      string lpszClassName, 
      string lpszWindowName,
      WindowStyle style, 
      int x, 
      int y, 
      int width, 
      int height, 
      IntPtr hwndParent, 
      IntPtr hMenu, 
      IntPtr hInst, 
      [MarshalAs(UnmanagedType.AsAny)] object pvParam);

    [DllImport("user32.dll", EntryPoint = "DestroyWindow", CharSet = CharSet.Unicode)]
    internal static extern bool DestroyWindow(IntPtr hwnd);

    public static void SetHotkey(IntPtr hotkeyWindow, HotkeyCombination value)
    {
      NativeMethods.SendHotkeyMessage(hotkeyWindow, HotkeyMessage.HKM_SETHOTKEY, value, IntPtr.Zero);
    }
    public static HotkeyCombination GetHotkey(IntPtr hotkeyWindow)
    {
      return NativeMethods.SendHotkeyMessage(hotkeyWindow, HotkeyMessage.HKM_GETHOTKEY, IntPtr.Zero, IntPtr.Zero);
    }

    public static System.Windows.Point GetMouseScreenPosition(System.Windows.Media.Visual relativeTo)
    {
      System.Windows.Point output;
      Win32Point w32Mouse = new Win32Point();
      NativeMethods.GetCursorPos(ref w32Mouse);

      System.Windows.Point position = new System.Windows.Point(w32Mouse.X, w32Mouse.Y);
      if (relativeTo != null)
      {
        output = relativeTo.PointFromScreen(position);
      }
      else
      {
        output = position;
      }
      return output;
    }

    [DllImport("user32.dll")]
    internal static extern bool GetCursorPos(ref Win32Point pt);

    [DllImport("gdi32.dll", CharSet = CharSet.Unicode)]
    internal static extern IntPtr CreateFont(
      int nHeight,
      int nWidth,
      int nEscapement,
      int nOrientation,
      int fnWeight,
      bool fdwItalic,
      bool fdwUnderline,
      bool fdwStrikeOut,
      uint fdwCharSet,
      uint fdwOutputPrecision,
      uint fdwClipPrecision,
      uint fdwQuality,
      uint fdwPitchAndFamily,
      String lpszFace
    );

    public static void SetFont(IntPtr control, IntPtr hFont)
    {
      NativeMethods.SendMessage(control, WindowMessage.WM_SETFONT, hFont, (IntPtr)1);
    }

  }
}
